package com.wxzhou.wangzhuan.service;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.wxzhou.wangzhuan.dto.config.ReaderConfigDto;
import com.wxzhou.wangzhuan.dto.reader.*;
import io.smallrye.mutiny.Uni;
import io.vertx.core.http.HttpMethod;
import io.vertx.core.json.JsonObject;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import okhttp3.MediaType;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import org.jboss.logging.Logger;

import java.util.Map;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

/**
 * 阅读接口服务
 */
@ApplicationScoped
public class ReaderApiService {
    private static final Logger LOG = Logger.getLogger(ReaderApiService.class);

    @Inject
    OkHttpClientFactory httpClientFactory;

    @Inject
    ConfigService configService;

    @Inject
    OkHttpConfig config;

    @Inject
    ObjectMapper objectMapper;

    /**
     * 获取token
     *
     * @param userid
     * @return
     */
    public Uni<ReaderResponseDto<ReaderTokenRespDto>> getToken(Long userid) {
        // 创建请求参数对象
        ReaderTokenReq tokenReq = new ReaderTokenReq();

        // 调用通用API方法
        return configService.getReaderConfig().onItem().transformToUni(readerConfigDto -> {
            // 设置应用ID和商户号
            tokenReq.setCid(readerConfigDto.getCid());
            tokenReq.setUid(String.valueOf(userid));

            // 调用通用API方法，使用RealNameCheckResponseDto作为响应类型（临时使用，实际应根据API返回定义专门的响应类型）
            return callReaderApiByPOST("/api/channel/getReadDomain", tokenReq, ReaderTokenRespDto.class, userid).onItem().transform(result -> {
                ReaderTokenRespDto data = result.getData();
                if (result.isSuccess() && data != null) {
                    // 解析成功，直接返回结果
                    return result;
                } else {
                    // 解析失败，返回错误信息
                    return ReaderResponseDto.fail("获取错误: " + (result.getMsg() != null ? result.getMsg() : "未知错误"), result.getCode() != 0 ? result.getCode() : 500);
                }
            });
        });
    }

    public Uni<ReaderResponseDto<ReaderUrlRespDto>> getUrl(Long userid, String jkey, String token) {
        // 创建请求参数对象
        ReaderUrlReq tokenReq = new ReaderUrlReq();
        tokenReq.set_jkey(jkey);
        tokenReq.setUid(String.valueOf(userid));
        tokenReq.setTk(token);
        tokenReq.setScheme("1");

        // 调用通用API方法，使用RealNameCheckResponseDto作为响应类型（临时使用，实际应根据API返回定义专门的响应类型）
        return callReaderApiByGET("/api/channel/getArticleRead", tokenReq, ReaderUrlRespDto.class, userid).onItem().transform(result -> {
            ReaderUrlRespDto data = result.getData();
            if (result.isSuccess() && data != null) {
                // 解析成功，直接返回结果
                return result;
            } else {
                // 解析失败，返回错误信息
                return ReaderResponseDto.fail("获取错误: " + (result.getMsg() != null ? result.getMsg() : "未知错误"), result.getCode() != 0 ? result.getCode() : 500);
            }
        });
    }

    public <T, R> Uni<ReaderResponseDto<T>> callReaderApiByPOST(String apiPath, R requestParams, Class<T> responseType, Long userId) {
        return configService.getReaderConfig().onItem().transformToUni(ReaderConfigDto -> {
            return callHuifuApiWithConfig(ReaderConfigDto, apiPath, requestParams, responseType, userId, HttpMethod.POST);
        });
    }

    public <T, R> Uni<ReaderResponseDto<T>> callReaderApiByGET(String apiPath, R requestParams, Class<T> responseType, Long userId) {
        return configService.getReaderConfig().onItem().transformToUni(ReaderConfigDto -> {
            return callHuifuApiWithConfig(ReaderConfigDto, apiPath, requestParams, responseType, userId, HttpMethod.GET);
        });
    }


    public <T, R> Uni<ReaderResponseDto<T>> callHuifuApiWithConfig(ReaderConfigDto configDto, String apiPath, R requestParams, Class<T> responseType, Long userId, HttpMethod method) {
        try {
            // 将请求参数对象转换为Map
            Map<String, Object> paramsMap = objectMapper.convertValue(requestParams, Map.class);

            // 构建完整的请求URL
            String requestUrl = configDto.getApiUrl() + apiPath;
            String userIdStr = userId != null ? String.valueOf(userId) : "default";

            // 获取全局和单源的信号量，用于并发控制
            return Uni.createFrom().item(() -> {
                Semaphore globalSemaphore = httpClientFactory.getGlobalSemaphore();
                Semaphore sourceSemaphore = httpClientFactory.getSourceSemaphore(userIdStr);

                try {
                    // 尝试获取全局并发许可，超时时间为配置的调用超时时间
                    if (!globalSemaphore.tryAcquire(config.callTimeout(), TimeUnit.MILLISECONDS)) {
                        throw new RuntimeException("全局并发限制");
                    }
                    // 尝试获取单源并发许可
                    if (!sourceSemaphore.tryAcquire(config.callTimeout(), TimeUnit.MILLISECONDS)) {
                        // 如果获取单源许可失败，需要释放已获取的全局许可
                        globalSemaphore.release();
                        throw new RuntimeException("源并发限制");
                    }
                    return new SemaphorePair(globalSemaphore, sourceSemaphore);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    throw new RuntimeException("获取并发许可被中断", e);
                }
            }).onItem().transformToUni(semaphorePair -> {
                // 执行HTTP请求
                if (method == HttpMethod.GET) {
                    return executeHttpGetRequest(paramsMap, requestUrl, responseType).onTermination().invoke(() -> {
                        // 请求完成后释放信号量
                        semaphorePair.globalSemaphore.release();
                        semaphorePair.sourceSemaphore.release();
                    });
                } else {
                    return executeHttpPostRequest(paramsMap, requestUrl, responseType).onTermination().invoke(() -> {
                        // 请求完成后释放信号量
                        semaphorePair.globalSemaphore.release();
                        semaphorePair.sourceSemaphore.release();
                    });
                }
            }).onFailure().recoverWithItem(throwable -> {
                LOG.error("调用汇付API失败: " + throwable.getMessage(), throwable);
                return ReaderResponseDto.error("调用汇付API失败: " + throwable.getMessage());
            });
        } catch (Exception e) {
            LOG.error("准备汇付API请求失败: " + e.getMessage(), e);
            return Uni.createFrom().item(ReaderResponseDto.error("准备汇付API请求失败: " + e.getMessage()));
        }
    }

    private <T> Uni<ReaderResponseDto<T>> executeHttpPostRequest(Map<String, Object> paramsMap, String requestUrl, Class<T> responseType) {

        return Uni.createFrom().item(() -> {
            try {
                // 4. 转换为JSON字符串
                String requestBodyJson = objectMapper.writeValueAsString(paramsMap);
                LOG.debugf("post请求阅读%s，参数：%s", requestUrl, requestBodyJson);

                // 5. 构建HTTP POST请求
                RequestBody body = RequestBody.create(requestBodyJson, MediaType.get("application/json; charset=utf-8"));
                Request request = new Request.Builder().url(requestUrl).post(body).addHeader("Content-type", "application/json").addHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)").build();

                // 6. 执行请求
                try (Response response = httpClientFactory.getHttpClient().newCall(request).execute()) {

                    // 8. 检查HTTP响应状态
                    if (response.isSuccessful() && response.body() != null) {
                        String responseBody = response.body().string();
                        return parseResponse(responseBody, responseType);
                    } else {
                        String errorMsg = "HTTP状态码: " + response.code();
                        if (response.body() != null) {
                            errorMsg += ", 响应: " + response.body().string();
                        }
                        return ReaderResponseDto.fail(errorMsg);
                    }
                }
            } catch (Exception e) {
                LOG.error("执行汇付HTTP请求异常: " + e.getMessage(), e);
                return ReaderResponseDto.fail("请求异常: " + e.getMessage());
            }
        });
    }

    /**
     * 执行汇付HTTP GET请求
     *
     * @param paramsMap    请求参数Map
     * @param requestUrl   请求URL
     * @param responseType 响应类型
     * @param <T>          响应泛型类型
     * @return 封装了响应数据的ReaderResponseDto
     */
    private <T> Uni<ReaderResponseDto<T>> executeHttpGetRequest(Map<String, Object> paramsMap, String requestUrl, Class<T> responseType) {
        return Uni.createFrom().item(() -> {
            try {
                // 构建带参数的GET请求URL
                StringBuilder urlBuilder = new StringBuilder(requestUrl);
                if (paramsMap != null && !paramsMap.isEmpty()) {
                    urlBuilder.append("?");
                    paramsMap.forEach((key, value) -> {
                        if (key != null && value != null) {
                            urlBuilder.append(key).append("=").append(value).append("&");
                        }
                    });
                    // 移除最后一个多余的&
                    if (urlBuilder.charAt(urlBuilder.length() - 1) == '&') {
                        urlBuilder.deleteCharAt(urlBuilder.length() - 1);
                    }
                }
                String fullUrl = urlBuilder.toString();
                LOG.debugf("阅读请求%s", fullUrl);

                // 构建HTTP GET请求
                Request request = new Request.Builder()
                        .url(fullUrl)
                        .get()
                        .addHeader("Content-type", "application/json")
                        .addHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)")
                        .build();

                // 执行请求
                try (Response response = httpClientFactory.getHttpClient().newCall(request).execute()) {
                    // 检查HTTP响应状态
                    if (response.isSuccessful() && response.body() != null) {
                        String responseBody = response.body().string();
                        return parseResponse(responseBody, responseType);
                    } else {
                        String errorMsg = "HTTP状态码: " + response.code();
                        if (response.body() != null) {
                            errorMsg += ", 响应: " + response.body().string();
                        }
                        return ReaderResponseDto.fail(errorMsg);
                    }
                }
            } catch (Exception e) {
                LOG.error("执行汇付HTTP GET请求异常: " + e.getMessage(), e);
                return ReaderResponseDto.fail("请求异常: " + e.getMessage());
            }
        });
    }

    /**
     * 解析响应体，将其转换为指定类型的对象并封装在ReaderResponseDto中
     *
     * @param responseBody 响应体字符串
     * @param cls          目标对象的Class类型
     * @param <T>          目标对象的泛型类型
     * @return 封装了目标对象的ReaderResponseDto
     */
    private <T> ReaderResponseDto<T> parseResponse(String responseBody, Class<T> cls) {
        try {
            LOG.debugf("响应参数:" + responseBody);
            // 将响应体解析为JSON对象
            JsonObject json = new JsonObject(responseBody);
            int code = json.getInteger("code", 500);
            String message = json.getString("msg", "");

            if (code == 0) {
                // 解析成功，将data字段转换为预期的对象
                if (json.containsKey("data")) {
                    JsonObject dataJson = json.getJsonObject("data");
                    if (dataJson != null) {
                        // 使用Jackson的ObjectMapper将Json对象转换为指定类型
                        String dataJsonStr = dataJson.encode();
                        T data = objectMapper.readValue(dataJsonStr, cls);
                        return ReaderResponseDto.success(data, message);
                    }
                }
                // 没有data字段或data为null时，返回成功但data为null
                return ReaderResponseDto.success(null, message);
            }
            // 响应失败
            return ReaderResponseDto.fail(message, code);
        } catch (Exception e) {
            LOG.error("解析响应体失败: " + e.getMessage(), e);
            return ReaderResponseDto.error("解析响应体失败: " + e.getMessage());
        }
    }

}
